package com.luobd.bpm.controller;


import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.luobd.bpm.business.process.dto.ProcessInstanceDetailDTO;
import com.luobd.bpm.business.process.dto.ProcessXmlDto;
import com.luobd.bpm.business.process.input.ProcessInstanceQueryInput;
import com.luobd.bpm.business.process.service.IProcessDefService;
import com.luobd.bpm.business.process.service.IProcessInstanceService;
import com.luobd.bpm.business.process.service.IProcessTaskService;
import com.luobd.bpm.common.ResponseData;
import com.luobd.bpm.common.ResponsePageData;
import com.luobd.bpm.common.utils.SpringContextUtil;
import com.luobd.bpm.dto.ProcessInstanceDTO;
import com.luobd.bpm.dto.ProcessInstanceHistoryDTO;
import com.luobd.bpm.dto.ProcessTaskDTO;
import com.luobd.bpm.input.ProcessInstanceTaskHistoryPageInput;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping(value = "/api/bpmn/instance")
@Api(tags = "流程实例模块")
public class ProcessInstanceController {

    @Autowired
    private RuntimeService runtimeService;


    @Autowired
    private HistoryService historyService;


    @Autowired
    protected IProcessInstanceService processInstanceService;



    @PostMapping(value = "/page")
    @ApiOperation(value = "分页查询流程任务")
    public ResponsePageData<ProcessInstanceDTO> page(@RequestBody ProcessInstanceQueryInput input) {
        ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery();
        if(StrUtil.isNotBlank(input.getProcessDefinitionId())) {
            query.processDefinitionId(input.getProcessDefinitionId());
        }
        long count = query.count();
        List<ProcessInstance> list = query.listPage(input.getStart(),input.getPageSize());
        List<ProcessInstanceDTO> result = list.stream().map(ProcessInstanceDTO::new).collect(Collectors.toList());
        return ResponsePageData.success(result,count);
    }


    @PostMapping(value = "/taskHistoryPage")
    @ApiOperation(value = "流程实例历史任务分页查询")
    public ResponsePageData<ProcessInstanceHistoryDTO> taskHistoryPage(@RequestBody ProcessInstanceTaskHistoryPageInput input) {
        HistoricTaskInstanceQuery instanceQuery = historyService.createHistoricTaskInstanceQuery();
        if(StrUtil.isNotBlank(input.getProcessInstanceId())) {
            instanceQuery.processInstanceId(input.getProcessInstanceId());
        }
        long count = instanceQuery.count();
        List<HistoricTaskInstance> instances = Collections.emptyList();
        if(count > 0) {
            instances = instanceQuery.orderByHistoricTaskInstanceStartTime().asc().listPage(input.getStart(), input.getPageSize());
        }
        List<ProcessInstanceHistoryDTO> result = Lists.newArrayList();

        for (HistoricTaskInstance item : instances) {
            ProcessInstanceHistoryDTO dto = new ProcessInstanceHistoryDTO();
            Date time = item.getEndTime();
            dto.setProcessInstanceId(item.getProcessInstanceId());
            dto.setTaskId(item.getId());
            dto.setTaskName(item.getName());
            dto.setCreateTime(LocalDateTimeUtil.of(item.getCreateTime()));
            if(time != null) {
                dto.setApproveTime(LocalDateTimeUtil.of(time));
            }
            dto.setCandidates(item.getAssignee());
            dto.setFinished(time != null);
            result.add(dto);
        }
        return ResponsePageData.success(result,count);
    }



    @GetMapping(value = "/delete")
    @ApiOperation(value = "删除流程实例")
    public ResponseData<Boolean> deleteById(@RequestParam(value = "id") String id) {
        runtimeService.deleteProcessInstance(id,"用户删除");
        return ResponseData.success(Boolean.TRUE);
    }


    @GetMapping(value = "/revoke")
    @ApiOperation(value = "撤销流程实例")
    public ResponseData<Boolean> revoke(@RequestParam(value = "id") String id) {
        return processInstanceService.revoke(id);
    }




    @GetMapping(value = "/get")
    @ApiOperation(value = "获取流程实例详情")
    public ResponseData<ProcessInstanceDetailDTO> get(@RequestParam(value = "instanceId") String instanceId) {
        ProcessInstanceDetailDTO processInstanceDetailDTO = getInstanceDetail(instanceId);
        if(processInstanceDetailDTO == null) {
            return ResponseData.error("流程实例信息不存在");
        }
        IProcessTaskService taskService = SpringContextUtil.getBean(IProcessTaskService.class);
        ResponseData<List<ProcessTaskDTO>> list = taskService.historyList(instanceId);
        processInstanceDetailDTO.setTasks(list.getData());
        return ResponseData.success(processInstanceDetailDTO);
    }




    private ProcessInstanceDetailDTO getInstanceDetail(String id) {
        ProcessInstanceDetailDTO dto = null;
        ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult();
        if(instance != null) {
            dto = new ProcessInstanceDetailDTO();
            dto.setProcessInstanceId(id);
            dto.setProcessDefinitionId(instance.getProcessDefinitionId());
            dto.setStartUserId(instance.getStartUserId());
        } else {
            HistoricProcessInstance singled = historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult();
            if(singled != null) {
                dto = new ProcessInstanceDetailDTO();
                dto.setProcessInstanceId(id);
                dto.setProcessDefinitionId(singled.getProcessDefinitionId());
            }

        }
        if(dto != null) {
            IProcessDefService defService = SpringContextUtil.getBean(IProcessDefService.class);
            ResponseData<ProcessXmlDto> data = defService.getProcessXml(dto.getProcessDefinitionId());
            dto.setProcessXmlDto(data.getData());
        }
        return dto;
    }




}
